package lbtest;
import lbtest.Biology;
import java.util.Arrays;

// 在Java中，没有明确写extends的类，编译器会自动加上extends Object。所以，任何类，除了Object，都会继承自某个类。
// Person称为超类（super class），父类（parent class），基类（base class），把Student称为子类（subclass），扩展类（extended class）。

// abstract class Person  使用abstract修饰的类就是抽象类。我们无法实例化一个抽象类
// 抽象类本身被设计成只能用于被继承，因此，抽象类可以强迫子类实现其定义的抽象方法，否则编译会报错。因此，抽象方法实际上相当于定义了“规范”。
// 面向抽象编程的本质就是：
// 上层代码只定义规范（例如：abstract class Person）；
// 不需要子类就可以实现业务逻辑（正常编译）；
// 具体的业务逻辑由不同的子类实现，调用者并不关心。

// 在Java中，一个类只能继承自另一个类，不能从多个类继承。但是，一个类可以实现多个interface 多个类逗号隔开
public class Person implements Biology {

    // 用final修饰的字段在初始化后不能被修改
    protected String name;

    protected int age = 0;

    // 实例可以访问静态字段，但是它们指向的其实都是父类的静态字段。所以，所有实例共享一个静态字段。 静态字段并不属于实例
    // 推荐使用 类名.静态字段来访问静态对象 类名.静态字段来访问静态对象
    // 静态方法属于class而不属于实例，因此，静态方法内部，无法访问this变量，也无法访问实例字段，它只能访问静态字段。
    public static int sex = 1;

    /** 构造函数 */
    // 创建对象实例的时候，按照如下顺序进行初始化：
    // 先初始化字段，例如，int age = 10;表示字段初始化为10，double salary;表示字段默认初始化为0，String name;表示引用类型字段默认初始化为null；
    // 执行构造方法的代码进行初始化。
    // 构造方法 java可多构造方法 实列化的时候根据传入参数自动调用合适的构造方法
    public Person(String name, int age) {
        System.out.println("构造函数获取");
        System.out.println(name);
        System.out.println(age);
    }

    public Person(String name) {
        this(name, 18); // 调用另一个构造方法Person(String, int)
    }

    /** this指向 */
    // this指向 方法内部，可以使用一个隐含的变量this，它始终指向当前实例。因此，通过this.field就可以访问当前实例的字段
    public void setName(String name) {
        this.name = name;
    }

    // 无命名冲突下可省略this关键字
    public String getName() {
        return name;
    }

    /** 可变参数 */
    // 可变参数 可变参数可以保证无法传入null  如果是String[] names可以传入null
    private int getAge(String... names) {
        System.out.println(Arrays.toString(names));  // names数据格式等同于 String[]
        return 3;
    }

    // 传入可变参数
    public int getNum() { return this.getAge("拉拉", "美美"); }


    /** 方法重载 */
    // 方法重载 方法名相同，但各自的参数不同，称为方法重载（Overload）
    // 方法重载的目的是，功能类似的方法使用同一名字，更容易记住，因此，调用起来更简单。
    // 举个例子，String类提供了多个重载方法indexOf()，可以查找子串：
    // int indexOf(int ch)：根据字符的Unicode码查找；
    // int indexOf(String str)：根据字符串查找；
    // int indexOf(int ch, int fromIndex)：根据字符查找，但指定起始位置；
    // int indexOf(String str, int fromIndex)根据字符串查找，但指定起始位置。
    public void hello(String name) {
        System.out.println("Hello, " + name + "!");
    }

    public void hello(String name, int age) {
        System.out.println("Hello, " + name + "!" + ",你的年龄" + age);
    }

    /** 多态 */
    // 定义一个被子类重写的方法
    // 用final修饰的方法不能被Override
    public void mulFunc() {
        System.out.println("父类方法mulFunc");
    }

    // abstract 抽象方法测试 把一个方法声明为abstract，表示它是一个抽象方法，本身没有实现任何方法语句。因为这个抽象方法本身是无法执行的，所以，Person类也无法被实例化。
    // public abstract void mulFuncAbstract();


    /** 接口 */
    @Override
    public void testInterface() {
        System.out.println("重写接口方法testInterface");
    }
}